#include <iostream>
#include <thread>
#include <string>
#include <chrono>
#include <vector>
#include <ctime>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "json.hpp"

#include "Group.hpp"
#include "User.hpp"
#include "public.hpp"

#define PASSWODE_LENGTH 50
#define NAME_LENHTH 50
#define BUFFER_SIZE 1024


using namespace std;
using json = nlohmann::json;

//记录当前系统登录的用户信息
User g_current_user;
//记录当前登录用户的好友列表信息
vector<User> g_current_friends_list;
//记录当前登录用户的群组列表信息
vector<Group> g_current_group_list;

//显示当前登录成功用户的基本信息
void show_current_user_data();
//接受用户受到消息的线程
void read_task_heandler(int client_fd);
//获取系统时间
string GetCurrentTime();
//主聊天页面程序
void MainMenu(int clientfd);

//help command handler
void help(int fd = 0 , string str = "");
//"chat " command handler
void chat(int, string);
//"addfriend " command handler
void add_friend(int, string);
//"create group " command handler
void create_group(int, string);
//"addgroup " command handler
void add_group(int, string);
//"groupchar" command handler
void group_chat(int, string);
//"loginout" command handler
void login_out(int, string);

//信号处理函数
void signal_handler(int signal);
int g_client_fd=-1;
#include <atomic>
std::atomic<bool> g_is_menu_running(false);
unordered_map<string, string> command_map = {
    {"help", "显示所有支持的命令，格式help"},
    {"chat", "一对一聊天，格式chat:friendid:message"},
    {"addfriend", "添加好友，格式addfriend:friendid"},
    {"creategroup","创建群组，格式creategroup:groupname:groupdesc"},
    {"addgroup", "创建群组，格式group:group_id"},
    {"groupchat","群聊，格式groupchat:group_id:message"},
    {"loginout","注销，格式loginout"}};

//注册系统支持的客户端命令处理：
unordered_map<string, function<void(int, string)>> command_handler_map ={
    {"help", help},
    {"chat", chat},
    {"addfriend", add_friend},
    {"creategroup", create_group},
    {"addgroup", add_group},
    {"groupchat", group_chat},
    {"loginout", login_out}};


int main(int argc, char **argv){
    if(argc < 3){
        cerr << "Usage invaild example: ./ExeNAME IpAddress Port" << endl;
        exit(1);
    }
    // 解析IP地址和端口号
    char *ip = argv[1];
    uint16_t port = atoi(argv[2]);
    
    //创建socket
    int clientfd = socket(AF_INET, SOCK_STREAM, 0);
    if(clientfd == -1){
        cerr<< " create socket error"<<endl;
        exit(-1);
    }

    //录入连接server服务器信息
    sockaddr_in server; 
    memset(&server, 0, sizeof(sockaddr_in));
    server.sin_family = AF_INET;
    server.sin_port = htons(port);
    server.sin_addr.s_addr = inet_addr(ip);

    //server 与 clientfd连接
    if(-1 == connect(clientfd, (sockaddr *)&server, sizeof(sockaddr_in))){
        cout<< "connect error" << endl;
        close(clientfd);
        exit(-1);
    }
    
    // 注册信号处理函数
    g_client_fd = clientfd;
    signal(SIGINT, signal_handler);
    
    
    //主业务
    for(;;){
        //显示首页面菜单 登录， 注册， 退出
        cout<<"********welcome**********"<< endl;
        cout<<"        1.login        "<<endl;
        cout<<"        2.register     "<<endl;
        cout<<"        3.quit         "<<endl;
        cout<<"please input your choice:";
        int choice = 0;
        cin>>choice;
        //处理读入缓冲区的回车，
        cin.get();
        switch(choice){
        case 1:
            {
                int id =0;
                char pwd[PASSWODE_LENGTH] = {0};
                cout<<" please input id:";
                cin>>id;
                cin.get();
                
                cout<<"please input password:";
                cin.getline(pwd, PASSWODE_LENGTH);

                json js;
                js["msgid"] = LOGIN_MSG;
                js["id"] = id;
                js["password"] = pwd;
                string request = js.dump();
                //发送服务器保证c风格的字符串,但是试验下不+1,.c_str():自动再size()位置置为'\0'
                int len = send(clientfd, request.c_str(), strlen(request.c_str())+1, 0);
                if(len == -1){
                    cerr<< "send reg msg error"<<endl;
                }else{
                    //接受服务器反馈
                    char buffer[BUFFER_SIZE] = {0};
                    len = recv(clientfd, buffer, BUFFER_SIZE, 0);
                    if(len == -1){
                        cerr<< "recv reg msg error"<<endl;
                    }else{
                        //反序列化
                        json response_js = json::parse(buffer);//获取json对象
                        //登录失败
                        if(response_js["errno"].get<int>() != 0){
                            cerr << response_js["errmsg"] <<endl;
                        }else{
                            //登录成功记录当前用户信息，好友信息，群组信息，离线消息
                            g_current_user.set_id(response_js["id"].get<int>());
                            /*response_js["name"]，它的返回值类型是 json 类型（更准确地说是 json::reference
                             或 json::const_reference，取决于对象本身是否是 const）。
                            */
                            g_current_user.set_name(response_js["name"].get<string>());//
                            //记录当前用户的好友信息
                            if(response_js.contains("friends")){
                                vector<string> vec = response_js["friends"];//
                                for(string &str : vec){ 
                                    json friend_js = json::parse(str); //反序列化:
                                    User user; 
                                    user.set_id(friend_js["id"].get<int>());
                                    user.set_name(friend_js["name"]);
                                    user.set_state(friend_js["state"]);
                                    g_current_friends_list.push_back(user);
                                }
                            }
                            //群组信息 之后再写
                            if(response_js.contains("groups")){
                                vector<string> vec = response_js["groups"];
                                for(string &str : vec){
                                    json group_js = json::parse(str);
                                    Group group;
                                    group.set_id(group_js["id"].get<int>());
                                    group.set_name(group_js["name"].get<string>());//json可以强转为string？
                                    group.set_desc(group_js["desc"].get<string>());

                                    vector<string> vec2 = group_js["users"];//返回的信息有id和name
                                    for(string &user_str : vec2){
                                        GroupUser group_user;
                                        json group_user_js = json::parse(user_str);
                                        group_user.set_id(group_user_js["id"].get<int>());
                                        group_user.set_name(group_user_js["name"].get<string>());
                                        group_user.set_state(group_user_js["state"].get<string>());
                                        group_user.set_role(group_user_js["role"].get<string>());
                                        
                                        group.get_Users().push_back(group_user);                                           
                                    }
                                    g_current_group_list.push_back(group);
                                }
                            }   

                            //显示登录成功用户的基本信息
                            show_current_user_data();
                            
                            //显示用户的离线消息
                            if(response_js.contains("offlinemsg")){
                                vector<string> vec = response_js["offlinemsg"];
                                for(string &str : vec){
                                    json js = json::parse(str);
                                    cout<< js["time"].get<string>() <<"["<< js["id"]<< "]"<< js["name"].get<string>() << " said: "<<js["msg"].get<string>()<<endl;
                                }
                            }

                            //登录成功
                            static int thread_read_cnt = 0;
                            if(thread_read_cnt == 0){
                                thread read_task(read_task_heandler, clientfd);
                                read_task.detach();
                                thread_read_cnt++;
                            }
                            //进入主界面
                            g_is_menu_running = true;
                            MainMenu(clientfd);
                        }
                    }
                }
            }
            break;
        case 2:
            {
                //注册
                char name[NAME_LENHTH] = {0};
                char pwd[PASSWODE_LENGTH] = {0};
                cout<< "user name:";
                cin.getline(name, NAME_LENHTH);
                cout<< "password:";
                cin.getline(pwd, PASSWODE_LENGTH);
                
                //序列化
                json js;
                js["msgid"] = REG_MSG;
                js["name"] = name;
                js["password"] = pwd;
                string request = js.dump();

                //发送
                int len = send(clientfd, request.c_str(), strlen(request.c_str()),0);
                if(len == -1){
                    cerr << "send reg msg error"<<endl;
                }else{
                    //接受服务器端反馈
                    char buffer[BUFFER_SIZE] ={0};
                    len = recv(clientfd, buffer, BUFFER_SIZE,0) ;
                    if(len == -1){
                        cerr << "recv reg msg error"<<endl;
                    }else{
                        cout << "lens: "<< len <<"buffer:"<< buffer <<endl;
                        //反序列化
                        json response_js = json::parse(buffer);
                        if(response_js["error"].get<int>() != 0){
                            cerr<< name << "is already exist, register failed"<<endl;
                        }else{
                            //注册成功
                            cout<< name << "register success, and user id: "<< response_js["id"]<<" , please remeber it!!!"<<endl;
                        }
                    }
                }
            }
            break;
        case 3:
            {
                //退出
                close(clientfd);
                exit(0);
            }
        default:
            cout<<"invaild input!!"<<endl;
        }
    }
    
    return 0;
}

//信号处理函数
void signal_handler(int signal) {
    if (signal == SIGINT) {
        cout << "\n接收到 Ctrl+C 信号，正在安全退出..." << endl;
        if (g_client_fd != -1) {
            login_out(g_client_fd, "");
            exit(0);
        }
    }
}


void read_task_heandler(int client_fd){
    while(g_is_menu_running){
        char buffer[BUFFER_SIZE] = {0};
        int len = recv(client_fd, buffer, BUFFER_SIZE, 0);
        if(len == -1 || len == 0){
            close(client_fd);
            exit(-1);
        }
        json js = json::parse(buffer);
        cout<<"debug: "<<buffer<<endl;
        //一对一聊天
        if(js["msgid"].get<int>() == ONE_CHAT_MSG){
            cout<< js["time"].get<string>() << "[" << js["id"].get<int>() << "]" << js["name"].get<string>() << ": " << js["msg"].get<string>() << endl;
            continue;
        }else if(js["msgid"].get<int>() == GROUP_CHAT_MSG){
            cout<<"group msg: ["<< js["group_id"]<<"]";
            cout<<js["time"].get<string>() << "["<< js["id"] <<"]" << js["name"].get<string>() << ": " << js["msg"].get<string>() << endl;
            continue;
        }
        
    }
}

void show_current_user_data()
{ 
    cout << "==============login user=====================" << endl;
    cout << "current login user => id:" << g_current_user.get_id() << " name:" << g_current_user.get_name() << endl;
    cout << "--------------friend list--------------------" << endl;
    if(!g_current_friends_list.empty()){
        for(User &user : g_current_friends_list){
            cout << user.get_id() << " " << user.get_name() <<" " << user.get_state() <<endl;
        }
    }
    cout << "-------------group list---------------------"<<endl;
    cout << "--------------show end----------------------" << endl;
}

string GetCurrentTime(){
    auto tt = chrono::system_clock::to_time_t(chrono::system_clock::now());
    struct tm *ptm = localtime(&tt);
    char date[60] = {0};
    sprintf(date, "%d-%02d-%02d %02d:%02d:%02d",
            (int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday,
            (int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec); 
    return string(date);
}

void MainMenu(int clientfd){ 
    help();
    char buffer[BUFFER_SIZE] = {0};
    while(g_is_menu_running){
        cin.getline(buffer, BUFFER_SIZE);  
        string command_buf(buffer);
        //存储命令
        string command;
        int index = command_buf.find(":");
        if(index == -1){
            //命令出错？
            help();//输出帮助信息
            // login_out(clientfd);//登出
        }else{
            command = command_buf.substr(0, index);
        }
        if(command_buf == "loginout"){
            login_out(clientfd,"");
            continue;
        }
        auto it = command_handler_map.find(command);
        if(it == command_handler_map.end()){
            cerr<< "invaild input command" <<endl;
            continue;
        }
        //调用命令,不是send是second
        it->second(clientfd, command_buf.substr(index+1, command_buf.size()-index));//size() = end()-1;
    }
}

void help(int fd, string args){
    cout << "===========command list ============"<<endl;
    for(auto &it : command_map){
        cout<< it.first << ":" << it.second <<endl;
    }
    cout<<endl;
}

//一对一聊天
void chat(int fd, string str){
    int index = str.find(":");//str_end = -1
    if(index == -1){
        cerr << "chat command format error" << endl;
    }
    int friend_id = atoi(str.substr(0,index).c_str());
    string message = str.substr(index + 1, str.size() - index);//
    
    json js;
    js["msgid"] = ONE_CHAT_MSG;
    js["id"] = g_current_user.get_id();//当前用户id
    js["name"] =  g_current_user.get_name();//当前用户名

    js["to"] = friend_id;
    js["msg"] = message;
    js["time"] = GetCurrentTime();
    
    string request = js.dump();
    int len = send(fd, request.c_str(), strlen(request.c_str())+1, 0);
    if(len == -1){
        cerr << "send one chat msg error"<< endl;
    }
}

//添加好友
void add_friend(int fd, string str){
    int friend_id = atoi(str.c_str());
    json js;
    js["msgid"] = ADD_FRIEND_MSG;
    js["id"] = g_current_user.get_id();
    js["friendid"] = friend_id;
    
    string request = js.dump();
    
    int len = send(fd, request.c_str(), strlen(request.c_str())+1, 0);
    if(len == -1){
        cerr << "send add friend msg error"<< endl;
    }
}

//创建群聊
void create_group(int clientfd, string str)
{
    int index = str.find(":");
    if (index == -1)
    {
        cerr << "creategroup command invalid!" << endl;
        return;
    }

    string group_name = str.substr(0, index);
    string group_desc = str.substr(index + 1, str.size() - index);

    json js;
    js["msgid"] = CREATE_GROUP_MSG;
    js["id"] = g_current_user.get_id();
    js["groupname"] = group_name;
    js["groupdesc"] = group_desc;

    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send creategroup msg error" << endl;
    }
}

//加入群聊
void add_group(int clientfd, string str)
{
    int group_id = atoi(str.c_str());

    json js;
    js["msgid"] = ADD_GROUP_MSG;
    js["id"] = g_current_user.get_id();
    // 统一字段名为groupid，与服务端保持一致
    js["group_id"] = group_id;

    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send addgroup msg error" << endl;
    }
}

//群聊消息
void group_chat(int clientfd, string str)
{
    int index = str.find(":");
    if (index == -1)
    {
        cerr << "creategroup command invalid!" << endl;
        return;
    }

    int group_id = atoi(str.substr(0, index).c_str());
    string message = str.substr(index + 1, str.size() - index);

    json js;
    js["msgid"] = GROUP_CHAT_MSG;
    js["id"] = g_current_user.get_id();
    js["name"] = g_current_user.get_name();
    js["group_id"] = group_id;
    js["msg"] = message;
    js["time"] = GetCurrentTime();

    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()) + 1, 0);
    if (len == -1)
    {
        cerr << "send grouochat msg error" << endl;
    }
}

//注销
void login_out(int clientfd, string)
{
    json js;
    js["msgid"] = LOGINOUT_MSG;
    js["id"] = g_current_user.get_id();
    string request = js.dump();

    int len = send(clientfd, request.c_str(), strlen(request.c_str()), 0);//其实不用发,server端自动断开。
    if (len == -1)
    {
        cerr << "send grouochat msg error, clientserver closed" << endl;
        g_is_menu_running = false;
        // exit(0);//是否是卡在clear上？
        g_current_friends_list.clear();
        g_current_group_list.clear();
    }else{
        g_is_menu_running = false;
        g_current_friends_list.clear();
        g_current_group_list.clear();
    }
}